<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue 2.0 响应式原理模拟</title>
</head>
<body>
<div id="app">
    <p>{{ message }}</p>
    <input type="text" @input="updateMessage">
</div>

<script>
    // Dep 类用于管理依赖关系
    class Dep {
        constructor() {
            this.subs = [];
        }

        addSub(sub) {
            this.subs.push(sub);
        }

        notify() {
            this.subs.forEach(sub => sub.update());
        }
    }

    // Observer 类用于拦截对象属性的 get 和 set 操作
    function observe(value) {
        if (!value || typeof value !== 'object') return;
        Object.keys(value).forEach(key => {
            defineReactive(value, key, value[key]);
        });
    }

    function defineReactive(obj, key, val) {
        const dep = new Dep();
        let childOb = observe(val); // 递归处理嵌套对象

        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter() {
                if (Dep.target) { // 收集依赖
                    dep.addSub(Dep.target);
                }
                return val;
            },
            set: function reactiveSetter(newVal) {
                if (newVal === val) return;
                val = newVal;
                childOb = observe(newVal); // 如果新值是对象，则也需要观察
                dep.notify(); // 触发更新
            }
        });
    }

    // Watcher 类用于监听数据变化并执行更新逻辑
    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm;
            this.getter = parsePath(expOrFn);
            this.cb = cb;
            this.value = this.get();
        }

        get() {
            Dep.target = this;
            const value = this.getter.call(this.vm, this.vm);
            Dep.target = null;
            return value;
        }

        update() {
            const oldValue = this.value;
            this.value = this.get();
            this.cb.call(this.vm, this.value, oldValue);
        }
    }

    // 解析表达式路径
    const bailRE = /[^\w.$]/;
    function parsePath(path) {
        if (bailRE.test(path)) return;

        const segments = path.split('.');
        return function (obj) {
            for (let i = 0; i < segments.length; i++) {
                if (!obj) return;
                obj = obj[segments[i]];
            }
            return obj;
        };
    }

    // 初始化应用
    const app = document.getElementById('app');
    const data = {
        message: 'Hello Vue!'
    };

    observe(data);

    function updateView() {
        app.querySelector('p').textContent = data.message;
    }

    new Watcher({}, 'message', updateView); // 初始化时立即调用一次

    app.querySelector('input').addEventListener('input', function(e) {
        data.message = e.target.value;
    });

    // 初始渲染
    updateView();
</script>
</body>
</html>